package com.sqlcheck.service.impl;

import com.sqlcheck.entity.ScanResult;
import com.sqlcheck.model.SqlStatement;
import com.sqlcheck.service.CompatibilityRuleEngine;
import com.sqlcheck.common.enums.DatabaseType;
import com.sqlcheck.entity.CompatibilityRule;
import com.sqlcheck.repository.CompatibilityRuleRepository;
import com.sqlcheck.util.EnumConverter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
@Service
public class CompatibilityRuleEngineImpl implements CompatibilityRuleEngine {

    private final CompatibilityRuleRepository ruleRepository;

    public CompatibilityRuleEngineImpl(CompatibilityRuleRepository ruleRepository) {
        this.ruleRepository = ruleRepository;
    }

    @Override
    public List<ScanResult> checkCompatibility(SqlStatement sqlStatement,
            DatabaseType sourceType,
            DatabaseType targetType,
            Long taskId) {
        List<ScanResult> results = new ArrayList<>();

        if (log.isDebugEnabled()) {
            String preview = sqlStatement.getContent();
            if (preview != null && preview.length() > 200) {
                preview = preview.substring(0, 200) + "...";
            }
            log.debug("[CompatCheck] source={} -> target={}, file={}, line={}, sqlPreview={}",
                    sourceType, targetType, sqlStatement.getSourceFile(), sqlStatement.getLineNumber(), preview);
        }

        // 从数据库加载所有规则
        List<CompatibilityRule> rules = loadActiveRules(sourceType, targetType);
        log.debug("[CompatCheck] 加载规则: source={}, target={}, 有效规则数={}",
                sourceType, targetType, rules != null ? rules.size() : 0);

        // 应用数据库规则
        results.addAll(applyDbRules(sqlStatement, rules, taskId));

        return results;
    }

    @Override
    public List<ScanResult> checkCompatibility(List<SqlStatement> sqlStatements,
            DatabaseType sourceType,
            DatabaseType targetType,
            Long taskId) {
        List<ScanResult> allResults = new ArrayList<>();

        for (SqlStatement statement : sqlStatements) {
            allResults.addAll(checkCompatibility(statement, sourceType, targetType, taskId));
        }

        return allResults;
    }

    /**
     * 从数据库加载活跃的兼容性规则
     */
    private List<CompatibilityRule> loadActiveRules(DatabaseType sourceType, DatabaseType targetType) {
        try {
            CompatibilityRule.DbType src = CompatibilityRule.DbType.valueOf(sourceType.name());
            CompatibilityRule.DbType tgt = CompatibilityRule.DbType.valueOf(targetType.name());
            List<CompatibilityRule> rules = ruleRepository.findActiveBySourceAndTarget(src, tgt);
            log.debug("[CompatCheck] 数据库规则加载: source={}, target={}, 规则数={}",
                    sourceType, targetType, rules != null ? rules.size() : 0);
            return rules;
        } catch (Exception e) {
            log.error("[CompatCheck] 规则加载失败: source={}, target={} - {}",
                    sourceType, targetType, e.getMessage(), e);
            return new ArrayList<>();
        }
    }

    /**
     * 应用数据库规则并直接构建ScanResult
     */
    private List<ScanResult> applyDbRules(SqlStatement sqlStatement, List<CompatibilityRule> rules, Long taskId) {
        List<ScanResult> results = new ArrayList<>();
        if (rules == null || rules.isEmpty()) {
            return results;
        }
        
        String content = sqlStatement.getContent();
        int totalMatches = 0;
        List<String> matchedRules = new ArrayList<>();
        
        for (CompatibilityRule rule : rules) {
            try {
                if (rule.getRulePattern() == null || rule.getRulePattern().isEmpty()) {
                    continue;
                }
                
                // 尝试使用带降级机制的正则表达式匹配
                PatternMatchResult matchResult = applyRulePatternWithFallback(rule, content);
                
                if (matchResult.hasMatches()) {
                    totalMatches++;
                    matchedRules.add(rule.getRuleName());

                    // 构建包含多个匹配项信息的描述
                    String enhancedDescription = rule.getDescription();
                    if (matchResult.allMatches.size() > 1) {
                        enhancedDescription += String.format(" (发现%d处匹配)", matchResult.allMatches.size());
                    }
                    
                    // 如果使用了降级模式，添加警告信息
                    if (matchResult.usedFallback) {
                        enhancedDescription += " [注意: 使用简化匹配模式，可能存在误报]";
                    }

                    // 直接构建ScanResult对象
                    ScanResult scanResult = new ScanResult();
                    scanResult.setTaskId(taskId);
                    scanResult.setStatementId(sqlStatement.getId());
                    scanResult.setStatementNumber(sqlStatement.getStatementNumber());
                    scanResult.setRuleId(rule.getRuleId());
                    scanResult.setRuleName(rule.getRuleName());
                    scanResult.setIssueType(mapCategoryToIssueType(rule.getCategory()));
                    scanResult.setSeverity(convertSeverity(rule.getSeverity()));
                    scanResult.setIssueDescription(enhancedDescription);
                    scanResult.setSuggestion(rule.getSuggestion());
                    scanResult.setFilePath(sqlStatement.getSourceFile());
                    scanResult.setLineNumber(sqlStatement.getLineNumber());
                    scanResult.setOriginalSql(sqlStatement.getContent()); // 使用完整的SQL语句
                    scanResult.setSuggestedSql(rule.getSuggestedSql());
                    scanResult.setAnalysisEngine("RULE"); // 设置分析引擎为规则引擎
                    scanResult.setAiOptimized(false); // 规则引擎结果未经AI优化
                    
                    results.add(scanResult);
                    
                    String patternInfo = matchResult.usedFallback ? 
                        String.format("原始模式失败，使用降级模式: %s", matchResult.usedPattern) :
                        String.format("使用原始模式: %s", matchResult.usedPattern);
                    
                    log.info("[CompatCheck] 规则命中: ruleId={}, 生成问题数=1 (实际匹配{}次), file={}, line={} | {}",
                            rule.getRuleId(), matchResult.allMatches.size(), 
                            sqlStatement.getSourceFile(), sqlStatement.getLineNumber(), patternInfo);
                }
            } catch (Exception e) {
                log.warn("规则应用失败: {} - {}", rule.getRuleId(), e.getMessage());
            }
        }
        
        log.debug("[CompatCheck] SQL语句:{} 规则匹配合计: {} 条, 规则名称:{}", sqlStatement.getContent(), totalMatches,
                String.join(",", matchedRules));
        return results;
    }

    /**
     * 规则模式匹配结果
     */
    private static class PatternMatchResult {
        final List<String> allMatches;
        final boolean usedFallback;
        final String usedPattern;
        
        PatternMatchResult(List<String> allMatches, boolean usedFallback, String usedPattern) {
            this.allMatches = allMatches != null ? allMatches : new ArrayList<>();
            this.usedFallback = usedFallback;
            this.usedPattern = usedPattern;
        }
        
        boolean hasMatches() {
            return !allMatches.isEmpty();
        }
    }
    
    /**
     * 带降级机制的规则模式应用
     * 优先使用准确的复杂正则表达式，失败时降级到简化模式
     */
    private PatternMatchResult applyRulePatternWithFallback(CompatibilityRule rule, String content) {
        String originalPattern = rule.getRulePattern();
        
        try {
            // 尝试使用原始（复杂）模式
            Pattern pattern = Pattern.compile(originalPattern, 
                Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
            Matcher matcher = pattern.matcher(content);
            
            List<String> matches = new ArrayList<>();
            while (matcher.find()) {
                matches.add(matcher.group());
            }
            
            if (!matches.isEmpty()) {
                return new PatternMatchResult(matches, false, originalPattern);
            } else {
                return new PatternMatchResult(new ArrayList<>(), false, originalPattern);
            }
            
        } catch (Exception e) {
            // 原始模式失败，尝试降级模式
            log.warn("[PatternFallback] 原始正则表达式失败 ruleId={}, 错误={}, 尝试降级模式", 
                rule.getRuleId(), e.getMessage());
            
            String fallbackPattern = getFallbackPattern(rule.getRuleId(), originalPattern);
            if (fallbackPattern != null) {
                try {
                    Pattern pattern = Pattern.compile(fallbackPattern, 
                        Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
                    Matcher matcher = pattern.matcher(content);
                    
                    List<String> matches = new ArrayList<>();
                    while (matcher.find()) {
                        matches.add(matcher.group());
                    }
                    
                    log.info("[PatternFallback] 成功使用降级模式 ruleId={}, 降级模式={}, 匹配数={}", 
                        rule.getRuleId(), fallbackPattern, matches.size());
                    
                    return new PatternMatchResult(matches, true, fallbackPattern);
                    
                } catch (Exception fallbackError) {
                    log.error("[PatternFallback] 降级模式也失败 ruleId={}, 降级模式={}, 错误={}", 
                        rule.getRuleId(), fallbackPattern, fallbackError.getMessage());
                    return new PatternMatchResult(new ArrayList<>(), true, fallbackPattern);
                }
            } else {
                log.error("[PatternFallback] 无可用降级模式 ruleId={}", rule.getRuleId());
                return new PatternMatchResult(new ArrayList<>(), false, originalPattern);
            }
        }
    }
    
    /**
     * 获取规则的降级模式
     */
    private String getFallbackPattern(String ruleId, String originalPattern) {
        // 优先从数据库中获取预配置的降级模式
        CompatibilityRule rule = null;
        try {
            // 通过ruleId查找规则，获取其fallbackPattern
            rule = ruleRepository.findByRuleId(ruleId);
            if (rule != null && rule.getFallbackPattern() != null && !rule.getFallbackPattern().trim().isEmpty()) {
                log.info("[PatternFallback] 使用数据库配置的降级模式 ruleId={}, fallback={}", 
                    ruleId, rule.getFallbackPattern());
                return rule.getFallbackPattern();
            }
        } catch (Exception e) {
            log.warn("[PatternFallback] 获取数据库降级模式失败 ruleId={}, error={}", ruleId, e.getMessage());
        }
        
        // 如果数据库中没有配置降级模式，则使用代码中的默认映射
        log.info("[PatternFallback] 使用代码默认降级模式 ruleId={}", ruleId);
        return getDefaultFallbackPattern(ruleId, originalPattern);
    }
    
    /**
     * 获取默认的降级模式（代码中硬编码的映射）
     */
    private String getDefaultFallbackPattern(String ruleId, String originalPattern) {
        // 针对特定规则提供默认降级模式
        switch (ruleId) {
            case "OR_FUNC_016": // Oracle字符串拼接||操作符
                return "\\s\\|\\|\\s|^\\|\\||\\|\\|$"; // 匹配前后有空格的||，或行开始/结束的||
                
            case "OR_SYNTAX_003": // Oracle注释格式
                return "--(?!\\s)"; // 保持原有模式，因为已经比较简单
                
            case "OR_NUM_001": // Oracle NUMBER类型  
                return "\\bNUMBER\\b"; // 简化为仅检测NUMBER关键字，忽略括号条件
                
            case "OR_CHAR_001": // Oracle CHAR长度限制
                return "\\bCHAR\\s*\\("; // 简化为检测任何CHAR(的模式
                
            // 可以为其他复杂规则添加降级模式
            default:
                // 对于没有预定义降级模式的规则，尝试一些通用简化
                if (originalPattern.contains("(?!") || originalPattern.contains("(?<!")) {
                    // 移除所有前瞻和后瞻断言，保留核心匹配
                    String simplified = originalPattern
                        .replaceAll("\\(\\?![^)]*\\)", "")  // 移除负向前瞻
                        .replaceAll("\\(\\?=[^)]*\\)", "")   // 移除正向前瞻
                        .replaceAll("\\(\\?<![^)]*\\)", "") // 移除负向后瞻
                        .replaceAll("\\(\\?<=[^)]*\\)", ""); // 移除正向后瞻
                    
                    // 清理可能产生的空组或多余符号
                    simplified = simplified.replaceAll("\\(\\)", "");
                    
                    return simplified.isEmpty() ? null : simplified;
                }
                return null; // 无法提供降级模式
        }
    }

    /**
     * 将规则分类映射到ScanResult的IssueType
     */
    private ScanResult.IssueType mapCategoryToIssueType(String category) {
        return EnumConverter.parseIssueType(category);
    }

    /**
     * 转换严重程度
     */
    private ScanResult.Severity convertSeverity(CompatibilityRule.Severity s) {
        if (s == null) {
            return ScanResult.Severity.INFO;
        }
        switch (s) {
            case HIGH:
                return ScanResult.Severity.HIGH;
            case MEDIUM:
                return ScanResult.Severity.MEDIUM;
            case LOW:
                return ScanResult.Severity.LOW;
            default:
                return ScanResult.Severity.INFO;
        }
    }
}